#!/usr/bin/perl
use strict;
use warnings;
use DBI;
use FindBin qw($Bin);
	# TODO:リンシャン牌とかセットしとかないと・・・
#use lib 'tools';
#use SourceCarp fatal => 1, warnings => 1;
#SourceCarp::report("test module\n");
# all = 3*(9*4)+(7*4)=136


my $dbname = "$Bin/m.db";
my $nodb;
my $dbh;
my ($cmd, $first, $second) = @ARGV;

if (grep /--nodb/, @ARGV) {
	$nodb = 1;
}

unless (defined $cmd) {
  my $rev = '$Revision: 15 $';
  err_out("need parameter $rev");
  exit(1);
}

# -----------
# DB open
# -----------

# init ならばDBファイル消す
unlink $dbname if $cmd eq "init" && -f $dbname;

if ($nodb) {
	# perl m.pl init --nodb
	err_out("nodb mode");
	$dbh = DBI->connect("dbi:SQLite:", "", "", {AutoCommit => 0});
}
else{
	$dbh = DBI->connect("dbi:SQLite:dbname=$dbname", "", "", {AutoCommit => 0});
}
$dbh->do("PRAGMA case_sensitive_like=on");

# ----------------
# command switch
# ----------------
if ($cmd eq "init") {
	# subcommand "nodb" -> nodb mode
	&init_main(\$dbh, $first);
}
elsif ($cmd eq "sute") {
	# subcommand "sute" sute home caret
	#                   sute E    0
	# perl m.pl sute E m1
	&sute_main(\$dbh, $first, $second);
}
else{
	# show all
	&show_main(\$dbh);
}

# -----------
# DB close
# -----------
$dbh->disconnect();
exit(0);
# ================================================================
sub sute_main
{
	my ($dbh, $home, $caret) = @_;
	
	if (defined $dbh && defined $home && defined $caret == 0) {
		err_out("need parameter sute home sute_hai caret");
		return;
	}
	
	# config table 取得
	my %config = getconfig($dbh);
	
	#log_out("NOW_HOME=$config{'NOW_HOME'}");
	#log_out("home=$home caret=$caret");
	
	# 宣告しているhomeとDBが待っているhomeが同じ
	if (exists $config{'NOW_HOME'} && $config{'NOW_HOME'} eq $home) {
		
		# 手牌をリストに入れる
		# E m1m2m5s1s4s4p2p3p4p4j2
		my $tehai = get_tehai($dbh, $home);
		my @tehai_list;
		push(@tehai_list, $tehai =~ /\w\d/g);
		
		# ツモ牌のキーを取得
		my $tsumo_key = $config{'TSUMO_KEY'};
		
		if ($caret == 14) {
			# ツモ牌を切る
			# TODO: 切った牌の順番とかも必要
			$$dbh->do("UPDATE hai SET has='E RIVER' WHERE key=$tsumo_key");
			
			# ツモ牌を河に捨てる
			my $q_home = $$dbh->quote($home);
			$$dbh->do("INSERT INTO river (sute_cnt, home, hai_key) VALUES($config{TSUMO_CNT}, $q_home, $tsumo_key)");
			
		}
		else{ 
			# ツモ牌以外を切る
		
			# caret から key を取得
			# 同じ牌があったら牌だけではどれを切ったかわからないので
			# 位置情報から切った牌のkeyを取得する
			my %caret2key = get_caret2key($dbh, $home);
			
			#&log_out("$tehai");
			#&log_out("$tehai_list[$caret] $caret2key{$caret}");
			
			# 牌を河に捨てる
			# TODO: 切った牌の順番とかも必要
			my $key = $caret2key{$caret};
			$$dbh->do("UPDATE hai SET has='E RIVER' WHERE key=$key");
			#$$dbh->commit();
			#my $rc = $$dbh->rollback() || die $dbh->errstr;
			#&log_out("rc=$rc");
			
			# ツモ牌を手牌に確定
			$$dbh->do("UPDATE hai SET has='$home' WHERE key=$tsumo_key");
			
			# caretの牌を河に捨てる
			my $q_home = $$dbh->quote($home);
			$$dbh->do("INSERT INTO river (sute_cnt, home, hai_key) VALUES($config{TSUMO_CNT}, $q_home, $key)");
			
		}
		
		# 次の手番へ
		# TODO: ポンとかチーの実装は？
		my $tsumo_cnt = $config{'TSUMO_CNT'};
		$tsumo_cnt++;
		my %next_tsumo = get_yama2tsumo($dbh, $tsumo_cnt);
		my $next_home  = get_nexthome($home);
		my %hash = (
			'NOW_HOME'  => $next_home,
			'TSUMO_CNT' => $tsumo_cnt,
			'TSUMO_KEY' => $next_tsumo{'key'},
			'TSUMO'     => $next_tsumo{'type'} . $next_tsumo{'num'},
			);
		setconfig($dbh, %hash);
		$$dbh->commit();
		
	}
	else{
		err_out("you are not home yet.");
	}
	
	show_main($dbh);
	return;
}

sub init_main
{
	my ($dbh) = @_;
	
	&initlize($dbh);
	
	my @list = ('E', 'S', 'W', 'N');
	&set_hai($dbh, \@list);
	
	# --------------------------
	# ツモ牌を config にセット
	# --------------------------
	my %config = getconfig($dbh);
	my $cnt = $config{'TSUMO_CNT'}; # ツモ牌の番号
	my $sth = $$dbh->prepare("SELECT * FROM hai WHERE tsumo_num == $cnt");
	$sth->execute();
	while(my @rec = $sth->fetchrow_array) {
		my ($key, $type, $num, $same, $has, $tsumo_num) = @rec;
		# print "TSUMO $type" . "$num\n"; # $#rec==0
		my %hash = ('TSUMO' => $type . $num, 'TSUMO_KEY' => $key);
		setconfig($dbh, %hash);
	}
	$sth->finish(); $sth = undef;
	
	# ---------------------------------
	# 残りの牌の枚数を config にセット
	# ---------------------------------
	my $n_sth = $$dbh->prepare("SELECT COUNT(*) FROM hai WHERE has='-'");
	$n_sth->execute();
	
	while(my @rec = $n_sth->fetchrow_array) {
		#print join(',', @rec);
		my $nokori = "@rec"; # $#rec==0
		my %hash = ('NOKORI' => $nokori);
		setconfig($dbh, %hash);
	}
	$n_sth->finish(); $n_sth = undef;
	
	$$dbh->commit();
	
	show_main($dbh);
	
}

sub show_main
{
	my ($dbh) = @_;
	
	# 表示メイン
	show_tehai($dbh, 'E');
	show_river($dbh, 'E');
	show_tehai($dbh, 'S');
	show_river($dbh, 'S');
	show_tehai($dbh, 'W');
	show_river($dbh, 'W');
	show_tehai($dbh, 'N');
	show_river($dbh, 'N');
	
	&show_tsumoyama($dbh);
	return ;
}

# 家の河を表示
sub show_river
{
	my ($dbh, $home) = @_;
	
	# 河の牌keyを取得
	my $q_home = $$dbh->quote($home);
	my $sth = $$dbh->prepare("SELECT hai_key FROM river WHERE home==$q_home");
	$sth->execute();
	
	# key から牌を取得
	my $h_sth = $$dbh->prepare("SELECT type,num FROM hai WHERE key==?");
	
	my $kawa_hai = "";
	while(my @rec = $sth->fetchrow_array) {
		foreach my $key ( @rec ) {
			$h_sth->execute($key);
			while (my @rec2 = $h_sth->fetchrow_array) {
				my ($type, $num) = @rec2;
				$kawa_hai .= "$type$num";
			}
		}
	}
	print "KAWA $home $kawa_hai\n";
	$sth->finish; $sth = undef;
	return ;
}

sub show_tsumoyama
{
	my ($dbh) = @_;
	
	#my %config = getconfig($dbh);
	#print "TSUMO $config{'TSUMO'}\n";
	
	my @list;
	
	# ------------------------
	# 山牌
	# ------------------------
	my $tsumo_array = $$dbh->selectall_arrayref("SELECT type,num FROM hai WHERE has='-' ORDER BY tsumo_num");
	#my $tsumo_array = $$dbh->selectall_arrayref("SELECT type,num FROM hai ORDER BY tsumo_num"); # 配った牌も表示
	foreach my $line (@$tsumo_array) {
		#print "@$line\n";
		#my ($key, $type, $num, $same, $has, $tsumo_num) = @$line;
		my ($type, $num) = @$line;
		push(@list, "$type$num");
	}
	
	print "NEXT ";
	foreach my $line ( @list ) {
		print $line;
	}
	print "\n";
	
	# ------------------------
	# 残りの牌の数、アクティブな家、ツモ牌、山牌の順位
	# ------------------------
	my $a_sth = $$dbh->prepare("SELECT * FROM config");
	$a_sth->execute();
	while (my @rec = $a_sth->fetchrow_array) {
		my ($key, $val) = @rec;
		print "$key $val\n";# STATSU E
	}
	
	return ;
}

sub set_hai
{
	my ($dbh, $r_list) = @_;
	
	# tsumo_num から一枚ずつ取得
	my $tsumo_cnt = 0;
	foreach my $cnt (1..13) {
		foreach my $home (@$r_list) {
			$$dbh->do("UPDATE hai SET has='$home' WHERE tsumo_num=$tsumo_cnt");
			$tsumo_cnt++;
		}
	}
	
	
	my %config = ('TSUMO_CNT' => $tsumo_cnt);
	setconfig($dbh, %config);
	
	$$dbh->commit();
	return;
}

sub show_tehai
{
	my ($dbh, $home) = @_;
	
	my $tehai = get_tehai($dbh, $home);
	&log_out("$home $tehai");
}

sub get_tehai
{
	my ($dbh, $home) = @_;
	
	my $sth = $$dbh->prepare("SELECT key,type,num,same,has FROM hai WHERE has=?");
	$sth->execute($home);
	
	my $tehai = "";
	while(my $item = $sth->fetchrow_arrayref) {
		#&log_out("a @$item");
		my ($type, $num) = ($item->[1], $item->[2]);
		$tehai .= "$type$num";
	}
	$sth->finish; $sth = undef;
	return $tehai;
}

# 同じ牌で違うものを区別する用(ピンズ5の赤とか)
sub get_caret2key
{
	my ($dbh, $home) = @_;
	my $sth = $$dbh->prepare("SELECT key,type,num,same,has FROM hai WHERE has=?");
	$sth->execute($home);
	
	my %hash;
	my $caret = 0;
	while(my $item = $sth->fetchrow_arrayref) {
		#&log_out("a @$item");
		my ($key, $type, $num, $same, $has) = @$item;
		$hash{$caret} = $key;
		$caret++;
	}
	$sth->finish; $sth = undef;
	return %hash;
}

sub initlize
{
	my ($dbh) = @_;
	
	#if ($dbON) {
	#	unlink $dbname if -f $dbname;
	#	$$dbh = DBI->connect("dbi:SQLite:dbname=$dbname", "", "", {AutoCommit => 0});
	#}
	#else{
	#	err_out("nodb mode");
	#	$$dbh = DBI->connect("dbi:SQLite:", "", "");
	#}
	#$$dbh->do("PRAGMA case_sensitive_like=on");
	#$$dbh->{AutoCommit} = 0;
	
	$$dbh->do("CREATE TABLE hai ( key INTEGER PRAIMARY KEY, type TEXT, num INTEGER, same INTEGER, has TEXT, tsumo_num INTEGER )");
	#$$dbh->do("CREATE INDEX idx_flg ON hai(key)");
	
	# -----------------
	# 牌のナンバリング
	# -----------------
	my $cnt=0;
  	foreach my $type ('m','s','p','z') {
		my @list = ($type eq 'j')? (1..7) : (1..9);
		foreach my $num (@list) {
			foreach my $same (0..3) {
				my $q_cnt  = $$dbh->quote($cnt);
				my $q_type = $$dbh->quote($type);
				my $q_num  = $$dbh->quote($num);
				my $q_same = $$dbh->quote($same);
				my $q_has  = $$dbh->quote('-');
				$$dbh->do("INSERT INTO hai (key,type,num,same,has) VALUES($q_cnt,$q_type,$q_num,$q_same,$q_has)");
				$cnt++;
			}
		}
	}
	
	# -------------------------
	# ツモ牌をランダムに並べる
	# -------------------------
	
	# 後で増えるかも知れないのでまだ配ってない牌 has = '-' を指定
	my $array_ref = $$dbh->selectcol_arrayref("SELECT key FROM hai WHERE has = '-'");
	
	# array shuffle
	&fisher_yates_shuffle( $array_ref );
	
	# -------------------------
	# ツモ牌のナンバリング
	# -------------------------
	my $tsumo_cnt = 0;
	foreach my $key ( @$array_ref ){
		#my $q_tsumo_cnt = $dbh->quote($tsumo_cnt);
		$$dbh->do("UPDATE hai SET tsumo_num=$tsumo_cnt WHERE key=$key");
		$tsumo_cnt++;
	}
	
	## DEBUG ツモ順を確認用
	#my $tsumo_array = $$dbh->selectall_arrayref("SELECT * FROM hai WHERE tsumo_num < 20 ORDER BY tsumo_num");
	#foreach my $line (@$tsumo_array) {
	#	print "@$line\n";#
	#	my ($key, $type, $num, $same, $has, $tsumo_num) = @$line;
	#	print "$key, $type, $num, $same, $has, $tsumo_num\n";
	#}
	## 
	
	# ------------------------
	# config table
	# ------------------------
	$$dbh->do("CREATE TABLE config ( key TEXT, val TEXT )");
	$$dbh->do("INSERT INTO config (key, val) VALUES('NOW_HOME','E')");
	$$dbh->do("INSERT INTO config (key, val) VALUES('TSUMO_CNT','0')");
	$$dbh->do("INSERT INTO config (key, val) VALUES('TSUMO_KEY','0')");
	$$dbh->do("INSERT INTO config (key, val) VALUES('TSUMO','dummy')");
	$$dbh->do("INSERT INTO config (key, val) VALUES('NOKORI','dummy')");
	
	$$dbh->do("CREATE TABLE river ( sute_cnt INTEGER PRAIMARY KEY, home TEXT, hai_key INTEGER )");
	$$dbh->commit();
	return ;
}

sub setconfig
{
	my ($dbh, %para) = @_;
	
	unless (defined $dbh) {
		err_out("not defined paramter dbh");
		return;
	}
	
	while (my ($key, $val) = each %para) {
		my $q_key = $$dbh->quote($key);
		my $q_val = $$dbh->quote($val);
		$$dbh->do("UPDATE config SET val=$q_val WHERE key==$q_key");
		#print "UPDATE config SET val=$q_val WHERE key==$q_key\n";
	}
	return ;
}

sub getconfig
{
	my ($dbh) = @_;
	my %hash;
	
	unless (defined $dbh) {
		err_out("not defined paramter dbh");
		return;
	}
	
	my $sth = $$dbh->prepare("SELECT key,val FROM config");
	$sth->execute();
	while (my @rec = $sth->fetchrow_array) {
		my ($key, $val) = @rec;
		$hash{$key} = $val;
	}
	$sth->finish(); $sth = undef;
	
	return (%hash);
}

sub get_yama2tsumo
{
	my ($dbh, $tsumo_num) = @_;
	
	unless (defined $dbh) {
		err_out("not defined paramter dbh");
		return;
	}
	
	my %hash;
	my $sth = $$dbh->prepare("SELECT * FROM hai WHERE tsumo_num==$tsumo_num");
	$sth->execute();
	while (my @rec = $sth->fetchrow_array) {
		#my ($key, $type, $num, $same, $has) = @rec;
		#$hash{'key','type','num','same','has'} = ($key, $type, $num, $same, $has);
		@hash{'key','type','num','same','has'} = @rec;
	}
	$sth->finish(); $sth = undef;
	
	return (%hash);
}

# 配列のシャッフル
# cookbook p.123
# &fisher_yates_shuffle( \@array );
sub fisher_yates_shuffle
{
	my $array = shift;
	my $i;
	for ($i = @$array; --$i; ) {
		my $j = int rand ($i+1);
		next if $i == $j;
		@$array[$i,$j] = @$array[$j,$i];
	}
}

sub get_nexthome
{
	my ($home) = @_;
	
	my %nexthome = (
		'E' => 'S',
		'S' => 'W',
		'W' => 'N',
		'N' => 'E',
	);
	
	return $nexthome{$home};
}

sub log_out
{
	print "@_\n";
}

sub err_out
{
	print STDERR "@_\n";
}

__END__

my %hai;
&initilize(\%hai, $all_num);
&set_hai('E', \%hai, $all_num);


sub set_hai
{
  my ($Iam, $hai, $all_num) = @_;
  foreach my $cnt (0..10) { # 11
    
    while (1) {
      my $r = int rand $all_num;
      if ($hai->{$r}->{'is'} eq '-') {
        $hai->{$r}->{'is'} = '$Iam';
        last;
      }
    }
  }
  return ;
}



sub initilize
{
  my ($hai, $all_num) = @_;
  my $key = 0;
  
  foreach my $type ('m','s','p','j') {
    my @list = (1..9);
    @list = (1..7) if $type eq 'j';
    foreach my $num (@list) {
      foreach my $same (0..3) {
        $hai->{$key} = {
            is   => '-',
            type => $type,
            num  => $num,
            same => $same,
        };
#        print "$key:$type,$num,$same\n";
        $key++;
      }
    }
  }
  return ;
}



__END__

sub set_hai
{
  my ($Iam, $all_num) = @_;
  
  foreach my (1..11) {
    while (1) {
      my $r = int rand $all_num;
      unless ()
        break;
      }
    }  
  }
}

sub initilize
{
  my ($all_num) = @_;
  my @ume;
  
  my $cnt = 1;

  # initilize
  foreach my $num (1..9) {
    foreach my $mai (1..4) {
       $m[$num][$mai] = { is => '-', key => $cnt}; $cnt++;
       $s[$num][$mai] = { is => '-', key => $cnt}; $cnt++;
       $p[$num][$mai] = { is => '-', key => $cnt}; $cnt++;
       # print "m[$num][$mai] $m[$num][$mai]->{cnt}\n";
       # print "s[$num][$mai] $s[$num][$mai]->{cnt}\n";
       # print "p[$num][$mai] $p[$num][$mai]->{cnt}\n";
    }
  }

  foreach my $num ($w..$N) {
    foreach my $mai (1..4) {
       $j[$num][$mai] = { is => '-', key => $cnt}; $cnt++;
        print "j[$num][$mai] $j[$num][$mai]->{key}\n";
    }
  }
  
  return ;
}

# 0..135 を返す
sub call_rand()
{
   my ($exists_list, $all_num) = @_;
   while (1) {
     my $r = int rand $all_num;
     unless (grep /$r/, @$exists_list) {
       return $r;
     }
   }
}
  
